#pragma once

#include "HttpRequest.hpp"

enum class HttpRecvStatus
{
    // 正在接收请求行
    RECV_HTTP_LINE = 0,
    // 正在接收请求头部
    RECV_HTTP_HEAD,
    // 正在接收正文
    RECV_HTTP_BODY,
    // 全部接收完毕（可以交付给上层了）
    RECV_HTTP_OVER,
    // 接收请求出错（并设置对应错误的状态码）
    RECV_HTTP_ERROR
};

// HTTP请求协议对应的上下文类
class HttpContext
{
private:
    // 响应状态码
    int _resp_statu_code;

    // 当前解析所处的阶段
    HttpRecvStatus _recv_statu;

    // 已经解析好的部分，就填充到这个请求对象里
    HttpRequest _http_request;

private:
    // 接收并解析请求行
    int RecvHttpLine(Buffer *buf)
    {
        // 判断当前状态
        if (_recv_statu != HttpRecvStatus::RECV_HTTP_LINE)
        {
            LOG(LogLevel::DEBUG) << "状态错误，只有RECV_HTTP_LINE状态可以接收请求行";
            return -1;
        }
        // 从缓冲区中读取一行
        string line = buf->GetLine();

        // 如果读取失败
        if (line == "")
        {
            // 如果缓冲区中数据量已经大于最大请求行的长度了，还是找不到换行符
            // 那么肯定是有问题的
            if (buf->ReadAbleSize() > RequestLineMaxLength)
            {
                LOG(LogLevel::DEBUG) << "请求行过长";
                // 把状态设置为错误
                _recv_statu = HttpRecvStatus::RECV_HTTP_ERROR;
                // 设置响应状态码
                _resp_statu_code = 414;
                return -1;
            }
            // 返回0，表示请求行不完整
            return 0;
        }

        // 如果获取到的请求行太长
        if (line.size() > RequestLineMaxLength)
        {
            LOG(LogLevel::DEBUG) << "请求行过长";
            // 把状态设置为错误
            _recv_statu = HttpRecvStatus::RECV_HTTP_ERROR;
            // 设置响应状态码
            _resp_statu_code = 414;
            return -1;
        }

        // 成功获取到一个正常的请求行
        // 那么就开始解析
        if (ParseHttpLine(line) < 0)
        {
            // 解析失败
            return -1;
        }

        // 请求行处理完毕把状态设置为解析请求头部
        _recv_statu = HttpRecvStatus::RECV_HTTP_HEAD;

        // 接收并且解析成功
        return 1;
    }
    // 解析请求行并填充_http_request
    int ParseHttpLine(string &line)
    {
        // 判断当前状态
        if (_recv_statu != HttpRecvStatus::RECV_HTTP_LINE)
        {
            LOG(LogLevel::DEBUG) << "状态错误，只有RECV_HTTP_LINE状态可以解析请求行";
            return -1;
        }

        // 使用正则表达式解析请求行,并且忽略大小写
        std::smatch matches;
        // 编写正则表达式，定义成static，因为正责表达式编译消耗高
        static std::regex r("(GET|HEAD|POST|PUT|DELETE) ([^?]*)(?:\\?(.*))? (HTTP/1\\.[01])(?:\n|\r\n)?",
                            std::regex::icase);

        // 使用正则表达式提取请求行的要素
        if (std::regex_match(line, matches, r) == false)
        {
            LOG(LogLevel::DEBUG) << "使用正则解析请求行失败"<<"[line]: ["<<line<<"]";
            perror("error: ");

            // 把状态设置为错误
            _recv_statu = HttpRecvStatus::RECV_HTTP_ERROR;
            // 设置响应状态码
            _resp_statu_code = 400;
            return -1;
        }

        // 填充_http_request

        // 填充请求方法
        _http_request._method = matches[1];
        // 把请求方法转成大写
        for (auto &e : _http_request._method)
        {
            // 如果是小写字母，就转成大写
            if (e >= 'a' && e <= 'z')
            {
                e -= 32;
            }
        }

        // 先URL解码，再填充uri
        _http_request._uri = Tool::UrlDecode(matches[2], false);

        // 先URL解码，再填充查询字符串
        string tmp = Tool::UrlDecode(matches[3], true);
        vector<string> querys;
        Tool::SepStr(tmp, "&", querys);

        for (auto &e : querys)
        {
            // 查询字符串的key和val是以=为分割符的
            string sep = "=";
            uint64_t pos = e.find(sep);
            if (pos == string::npos)
            {
                LOG(LogLevel::DEBUG) << "解析查询字符串失败";
                // 把状态设置为错误
                _recv_statu = HttpRecvStatus::RECV_HTTP_ERROR;
                // 设置响应状态码
                _resp_statu_code = 400;
                return -1;
            }
            // 查询字符串的key和val
            string key = e.substr(0, pos);
            string val = e.substr(pos + sep.size());

            // 填充查询字符串
            _http_request.InsertParam(key, val);
        }
        // 填充协议版本
        _http_request._version = matches[4];

        // 返回1表示解析完成
        return 1;
    }

    // 接收请求报头
    int RecvHttpHead(Buffer *buf)
    {
        // 判断当前状态
        if (_recv_statu != HttpRecvStatus::RECV_HTTP_HEAD)
        {
            LOG(LogLevel::DEBUG) << "状态错误，只有RECV_HTTP_HEAD状态可以接收请求头部";
            return -1;
        }
        while (true)
        {
            // 从缓冲区中读取一行
            string line = buf->GetLine();

            // 如果读取失败
            if (line == "")
            {
                // 如果缓冲区中数据量已经大于最大的 行 的长度了，还是找不到换行符
                // 那么肯定是有问题的
                if (buf->ReadAbleSize() > RequestLineMaxLength)
                {
                    LOG(LogLevel::DEBUG) << "请求报头对应的行过长";
                    // 把状态设置为错误
                    _recv_statu = HttpRecvStatus::RECV_HTTP_ERROR;
                    // 设置响应状态码
                    _resp_statu_code = 414;
                    return -1;
                }
                // 返回0，表示请求报头对应的行不完整
                return 0;
            }

            // 如果获取到的行太长
            if (line.size() > RequestLineMaxLength)
            {
                LOG(LogLevel::DEBUG) << "请求报头对应的行过长";
                // 把状态设置为错误
                _recv_statu = HttpRecvStatus::RECV_HTTP_ERROR;
                // 设置响应状态码
                _resp_statu_code = 414;
                return -1;
            }

            // 如果读取到空行，就代表请求报头全部解析完成了
            if (line == "\r\n" || line == "\n")
            {
                // 结束循环
                break;
            }

            // 拿到一个正常的请求报头对应的行
            // 就开始逐行解析
            if (ParseHttpHead(line) < 0)
            {
                // 请求报头解析失败
                return -1;
            }
        }

        // 设置状态为接收请求正文
        _recv_statu = HttpRecvStatus::RECV_HTTP_BODY;

        // 接收完成，返回>0的结果表示成功
        return 1;
    }

    // 解析请求报头并填充_http_request
    int ParseHttpHead(string &line)
    {
        // 判断当前状态
        if (_recv_statu != HttpRecvStatus::RECV_HTTP_HEAD)
        {
            LOG(LogLevel::DEBUG) << "状态错误，只有RECV_HTTP_HEAD状态可以解析请求头部";
            return -1;
        }

        //去除一下末尾的换行符
        if (line.back() == '\n')
        {
            line.pop_back();
        }
        if (line.back() == '\r')
        {
            line.pop_back();
        }

        string sep = ": ";
        // 查找分隔符
        uint64_t pos = line.find(sep);
        if (pos == string::npos)
        {
            LOG(LogLevel::DEBUG) << "解析请求报头失败";
            // 把状态设置为错误
            _recv_statu = HttpRecvStatus::RECV_HTTP_ERROR;
            // 设置响应状态码
            _resp_statu_code = 400;
            return -1;
        }
        string key = line.substr(0, pos);
        string val = line.substr(pos + sep.size());

        // 填充请求报头
        _http_request.InsertHead(key, val);

        // 返回>0的结果表示成功
        return 1;
    }

    // 接收请求正文并填充_http_request
    int RecvHttpBody(Buffer *buf)
    {
        // 判断当前状态
        if (_recv_statu != HttpRecvStatus::RECV_HTTP_BODY)
        {
            LOG(LogLevel::DEBUG) << "状态错误，只有RECV_HTTP_BODY状态可以接收请求正文";
            return -1;
        }
        // 计算请求正文的长度
        uint64_t body_size = _http_request.ContenLength();

        

        // 从缓冲区读取请求正文
        if (body_size != 0)
        {
            // 因为可能之前读取过一部分正文
            // 计算剩余的要读取的正文长度
            uint64_t remainder_body_size = body_size - _http_request._body.size();
            string in;
            if (buf->ReadAsString(&in, remainder_body_size) < remainder_body_size)
            {
                // 请求正文不完整
                _http_request._body += in;
                return 0;
            }

            // 请求正文完整
            _http_request._body += in;
        }

        // 设置状态为接收请求完毕
        _recv_statu = HttpRecvStatus::RECV_HTTP_OVER;

        // 接收完成，返回>0的结果表示成功
        return 1;
    }

public:
    HttpContext()
        : _resp_statu_code(200),
          _recv_statu(HttpRecvStatus::RECV_HTTP_LINE)
    {
    }
    // 重置上下文对象存储的内容
    void Reset()
    {
        _resp_statu_code = 200;
        _recv_statu = HttpRecvStatus::RECV_HTTP_LINE;
        _http_request.ReSet();
    }
    // 返回响应状态码
    int ResponseStatuCode()
    {
        return _resp_statu_code;
    }

    // 返回解析完成的报文对应的HttpRequest对象
    HttpRequest &Request()
    {
        // 如果当前状态不是处理完成的状态
        if (_recv_statu == HttpRecvStatus::RECV_HTTP_OVER)
        {
            return _http_request;
        }
        else
        {
            LOG(LogLevel::WARNING) << "请求报文处理时，状态不为RECV_HTTP_OVER，但是依旧尝试获取报文";
        }
        return _http_request;
    }
    // 返回当前解析的阶段（状态）
    HttpRecvStatus RecvStatu()
    {
        return _recv_statu;
    }
    // 分阶段接收并解析请求报文
    int RecvRequest(Buffer *buf)
    {
        // 返回值：
        // 大于0表示成功
        // 等于0表示接收失败（缓冲区中数据不完整）
        // 小于0表示错误
        int ret = 0;
        switch (_recv_statu)
        {
        case HttpRecvStatus::RECV_HTTP_LINE: // 接收并解析请求行
            if ((ret = RecvHttpLine(buf)) <= 0)
            {
                return ret;
            }
        case HttpRecvStatus::RECV_HTTP_HEAD: // 接收并解析请求头部
            if ((ret = RecvHttpHead(buf)) <= 0)
            {
                return ret;
            }
        case HttpRecvStatus::RECV_HTTP_BODY: // 接收并解析请求正文
            if ((ret = RecvHttpBody(buf)) <= 0)
            {
                return ret;
            }
        case HttpRecvStatus::RECV_HTTP_OVER: // 接收和解析全部完成
            return 1;
        case HttpRecvStatus::RECV_HTTP_ERROR: // 接收（或解析）异常
            return -1;
        default:
            LOG(LogLevel::WARNING) << "请求报文处理时，_recv_statu状态异常";
            return -1;
        }
    }
};